import fetch from "isomorphic-fetch"
import {message} from "antd"
import {HOST} from "../project-config"
import {Modal} from "antd"
import AuthenticationError from "./errors/authentication"
import BusinessError from "./errors/business"
import TimeOutError from "./errors/timeout"
import InternalError from "./errors/internal"
import AuthorizationError from "./errors/authorization"

//请求超时设置(秒)
const timeoutSecond = 10

const createTokenHeader = (header) => {
  const headers = !header ? {} : {
    ...header
  }
  const token = localStorage.getItem('token')
  if (token) {
    headers['Authorization'] = token
  }
  return headers
}

function resolve(obj, p) {
  if (!obj) return {}
  return Object.entries(obj).map(([k, v]) => {
    const _k = p ? `${p}.${k}` : k
    if (typeof v !== 'object' || v instanceof Array) {
      return {key: _k, value: v}
    } else {
      return resolve(v, _k)
    }
  })
}

function entries(obj) {
  const es = resolve(obj)
  return es ? es.flat(Infinity) : []
}

function createParamString(obj) {
  return entries(obj).map(({key, value}) => `${key}=${encodeURIComponent(value)}`).join('&')
}

const networkResponse = (fetchPromise, errorHandler) => {
  const promise = fetchPromise
    .then(async response => {
      if (response.status === 401) {
        const json = await response.json()
        throw new AuthenticationError(json.message, json.code)
      }

      if (response.status === 403) {
        const json = await response.json()
        throw new AuthorizationError(json.message, json.code)
      }

      if (response.status === 500) {
        const json = await response.json()
        throw new InternalError(json.message, json.code)
      }
      return response.json()
    })
    .then(json => {
      //成功状态
      if (json && json.status === 1) {
        return json.data;
      }
      //内部错误
      if (json.code - 0 === 500) {
        throw new InternalError(json.message, json.code)
      }
      //业务异常
      if (!errorHandler) {
        message.error(`${json.message}(code:${json.code})`)
        throw new BusinessError(json.message, json.code)
      } else if (typeof errorHandler === "function") {
        errorHandler(json)
      } else {
        throw new BusinessError(json.message, json.code)
      }
    }).catch((e) => {
      //401异常系统全局处理
      if (e.name === AuthenticationError.NAME) {
        if (!window.authLock) {
          window.authLock = true
          sessionStorage.setItem('redirect_url', window.location)
          Modal.error({
            title: '提示',
            content: `${e.message}(code:${e.code})`,
            onOk: () => {
              window.location.href = "/login"
            }
          })
        }
        return Promise.reject()
      } else if (e.name === AuthorizationError.NAME) {
        Modal.error({
          title: '提示',
          content: `${e.message}(code:${e.code})`
        })
        return Promise.reject()
      } else if (e.name === BusinessError.NAME) {
        //如果接口调用自定义异常处理，抛出异常供接口调用者处理
        if (errorHandler) {
          throw e;
        }
      } else if (e.name === TimeOutError.NAME) {
        message.error(`请求超时,请重试 [${e.message}]`)
        return Promise.reject()
      } else if (e.name === InternalError.NAME) {
        message.error(`系统内部错误,请联系管理员 [${e.message}]`)
        return Promise.reject()
      } else {
        message.error(`系统内部错误,请联系管理员 [${e.message}]`)
        return Promise.reject()
      }
    })
  return promise
}


function submitJSON(url, postData, method, errorHandler) {
  const headers = createTokenHeader({
    "Content-type": "application/json;charset=UTF-8"
  })
  return networkResponse(Promise.race([
      fetch(`${HOST}${url}`, {
        method: method,
        credentials: 'include',
        headers: headers,
        mode: "cors",
        body: JSON.stringify(postData || {})
      }),
      new Promise(function (resolve, reject) {
        setTimeout(() => reject(new TimeOutError('Request_Timeout')), timeoutSecond * 1000)
      })]),
    errorHandler
  )
}

function submitParam(url, postData, method, errorHandler) {
  //formData可能造成不能提交
  const formData = new FormData()
  Object.entries(postData || {}).forEach(([k, v]) => {
    formData.append(k, v)
  })
  const headers = createTokenHeader()
  let paramString
  if (postData) {
    paramString = createParamString(postData)
  }
  const getURL = paramString ? `${HOST}${url}?${paramString}` : `${HOST}${url}`
  return networkResponse(fetch(getURL, {
      method: method,
      credentials: "include",
      headers: headers,
      mode: "cors",
      // body: formData
    }),
    errorHandler)
}

function submitQueryString(url, params, method, errorHandler) {
  const headers = createTokenHeader()
  let paramString
  if (params) {
    paramString = createParamString(params)
  }
  const getURL = paramString ? `${HOST}${url}?${paramString}` : `${HOST}${url}`
  return networkResponse(fetch(getURL, {
      method: method,
      headers: headers,
      credentials: "include",
      mode: "cors",
    }),
    errorHandler)
}

export function postJSON(url, postData, errorHandler) {
  return submitJSON(url, postData, "POST", errorHandler)
}

export function postParam(url, postData, errorHandler) {
  return submitParam(url, postData || {}, "POST", errorHandler)
}

export function putJSON(url, postData, errorHandler) {
  return submitJSON(url, postData, "PUT", errorHandler)
}

export function putParam(url, postData, errorHandler) {
  return submitParam(url, postData, "PUT", errorHandler)
}

export function get(url, params, errorHandler) {
  return submitQueryString(url, params, "GET", errorHandler)
}

export function del(url, params, errorHandler) {
  return submitQueryString(url, params, "DELETE", errorHandler)
}

export const OK = 'OK'